<?php
/**
 * Created by PhpStorm.
 * User: krystal
 * Date: 2019/4/22
 * Time: 16:10
 */

namespace app\common\model;


use XznsTools\search\Elasticsearch;
use app\common\lib\exception\ApiException;
use think\Cache;
use think\Exception;
use XznsTools\cache\CacheManage;

/**
 * 咨询师
 * Class ZhunleCounselor
 * @package app\common\model
 */
class ZhunleCounselor extends Base
{
    const COUNSELOR_HOT_IDS = 'counselor:hot:ids';//热门咨询师id
    const CACHE_TIME = 86400 * 7;//缓存时间
    protected $table = 'wechat_backup_07_18_14_43_00.zhunle_counselor';

    /**
     * 保存或编辑咨询师信息
     * @param array $data
     * @param int $cid
     * @return void
     * @throws ApiException
     * @throws \Exception
     */
    public function saveCounselor(array $data, $cid)
    {
        $uid = $data['uid'];
        try
        {
            // 更新咨询师信息
            $this->save($data, ['id' => $cid]);
        }
        catch (\Exception $e)
        {
            throw new ApiException('服务异常', 200, config('code.error'));
        }
        // 更新咨询师详情缓存
        CacheManage::getInstance()->setCacheConfig('counselor_info', $cid)
            ->setCache($data, 'details', true);
        //更新用户咨询师id缓存
        CacheManage::getInstance()->setCacheConfig('counselor_info', $uid)
            ->sAddIocData([$cid], 'list', function () use ($uid)
            {
                return $this->getUserCounselorIdFromData($uid);
            });

    }

    /**
     * 获取咨询师列表id
     * @param array $map //筛选条件(type,price,level,grade,search)
     * @return array|bool
     * @throws \Exception
     */
    public function getCounselorLists($map = [])
    {
//        return $this->getCounselorListsFromElasticsearch($map);
        $level_start = 0;
        $level_end = 999999;
        $grade_start = 0;
        $grade_end = 999999;
        $price_start = 0;
        $price_end = 999999;

        if ($map['search'] == '')
        {
            //根据等级进行筛选
            switch (true)
            {
                case $map['level'] == 1:
                    $level_end = 1;
                    break;
                case $map['level'] == 2:
                    $level_start = 1;
                    $level_end = 2;
                    break;
                case $map['level'] == 3:
                    $level_start = 2;
                    $level_end = 3;
                    break;
                case $map['level'] == 4:
                    $level_start = 3;
                    break;
            }
            //根据价格进行筛选
            switch (true)
            {
                case $map['price'] == 1:
                    $price_end = 100;
                    break;
                case $map['price'] == 2:
                    $price_start = 100;
                    $price_end = 300;
                    break;
                case $map['price'] == 3:
                    $price_start = 300;
                    $price_end = 500;
                    break;
                case $map['price'] == 4:
                    $price_start = 500;
                    break;
            }
            //根据评分进行筛选
            switch (true)
            {
                case $map['grade'] == 1:
                    $grade_start = 5;
                    break;
                case $map['grade'] == 2:
                    $grade_start = 4;
                    $grade_end = 5;
                    break;
                case $map['grade'] == 3:
                    $grade_start = 3;
                    $grade_end = 4;
                    break;
                case $map['grade'] == 4:
                    $grade_end = 3;
                    break;
            }
            //根据类型进行筛选
            if ($map['type'] == 0)
            {
                $where  ="(star_level >= $grade_start AND star_level < $grade_end) AND ((divination_level > $level_start AND divination_level <= $level_end) OR  (stargazer_level > $level_start AND stargazer_level <= $level_end)) AND ((divination_price > $price_start AND divination_price <= $price_end) OR  (stargazer_price > $price_start AND stargazer_price <= $price_end))";
            } else
            {
                //根据占星进行筛选
                if ($map['type'] == 1)
                {
                    $level_name = 'stargazer_level';
                    $price_name = 'stargazer_price';
                } //根据提问进行筛选
                else
                {
                    $level_name = 'divination_level';
                    $price_name = 'divination_price';
                }

                $where  ="star_level >= $grade_start AND star_level < $grade_end AND $level_name > $level_start AND $level_name <= $level_end AND $price_name > $price_start AND $price_name <= $price_end";
            }
        }//根据搜索进行筛选
        else{
            $search = $map['search'];
            $where = "nickname like '%$search%'";
        }

        //判断是否过滤自己
        if ($map['filter_self'])
        {
            $uid = $map['uid'];
            $where .=" AND uid <> $uid";
        }

        //获取符合的咨询师id
        try
        {
            $cids = $this
                ->where($where)
                ->column('id');
        }
        catch (\Exception $e)
        {
            $this->error = '获取咨询师列表失败';
            return false;
        }

        $per_page = 10;// 当前咨询师每页显示数量
        //获取分页数据
        $data_list = getPaginatorData(count($cids),$map['page'],$per_page);

        //获取分页后的咨询师id数组
        $cids = array_slice($cids, $data_list['start'], $per_page);

        unset($data_list['start']);
        unset($data_list['end']);

        // 从缓存中获取咨询师信息
        $data_list['data'] = $this->batchGetInfoByIds($cids);

        return $data_list;
    }

    /**
     * Elasticsearch 进行咨询师搜索
     * @param $map
     * @return array
     * @throws \Exception
     */
    public function getCounselorListsFromElasticsearch($map)
    {
        $query = [];

        if ($map['search'])
        {
            $query['bool']['must'][] = ['match' => ['nickname' => $map['search']]];
        }

        if ($map['filter_self'])
        {
            $query['bool']['must_not'][] = ['match' => ['uid' => $map['uid']]];
        }

        // 根据评分进行筛选
        if ($map['grade'])
        {
            switch ($map['grade'])
            {
                case 1:
                    $query['bool']['must'][] = ['match' => ['star_level' => 5]];
                    break;
                case 2:
                    $query['bool']['must'][] = ['match' => ['star_level' => 4]];
                    break;
                case 3:
                    $query['bool']['must'][] = ['match' => ['star_level' => 3]];
                    break;
                case 4:
                    $query['bool']['must'][] = ['range' => ['star_level' => ['lt' => 3]]];
                    break;
            }
        }
        // 搜索占星师
        if ($map['type'] === 1)
        {
            $query['bool']['must'][] = ['range' => ['stargazer_level' => ['gte' => 1]]];
        }// 搜索提问师
        elseif ($map['type'] === 2)
        {
            $query['bool']['must'][] = ['range' => ['divination_level' => ['gte' => 1]]];
        }
        // 按价格搜索
        if ($map['price'])
        {
            switch ($map['price'])
            {
                case 1:
                    $priceCond = ['lte' => 100];
                    break;
                case 2:
                    $priceCond = ['gt' => 100, 'lte' => 300];
                    break;
                case 3:
                    $priceCond = ['gt' => 300, 'lte' => 500];
                    break;
                case 4:
                default:
                    $priceCond = ['gt' => 500];
                    break;
            }
            $query['bool']['must'][] = [
                'bool' => [
                    'should' => [
                        ['range' => ['stargazer_price' => $priceCond]],
                        ['range' => ['divination_price' => $priceCond]],
                    ]
                ]
            ];
        }
        // 按评分星级搜索
        if ($map['level'])
        {
            switch ($map['level'])
            {
                case 1:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['lte' => 5]]],
                                ['range' => ['divination_level' => ['lte' => 5]]],
                            ]
                        ]
                    ];
                    break;
                case 2:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['gt' => 5, 'lte' => 4]]],
                                ['range' => ['divination_level' => ['gt' => 5, 'lte' => 4]]],
                            ]
                        ]
                    ];
                    break;
                case 3:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['gt' => 4, 'lte' => 3]]],
                                ['range' => ['divination_level' => ['gt' => 4, 'lte' => 3]]],
                            ]
                        ]
                    ];
                    break;
                case 4:
                default:
                    $query['bool']['must'][] = [
                        'bool' => [
                            'should' => [
                                ['range' => ['stargazer_level' => ['gt' => 3]]],
                                ['range' => ['divination_level' => ['gt' => 3]]],
                            ]
                        ]
                    ];
                    break;
            }
        }

        $data = Elasticsearch::getInstance()
            ->setIndex('counselor')
            ->setType('Elasticsearch')
            ->setPargeSize(10)
            ->setPageNum($map['page'])
            ->setParamFields('id')
//            ->setParamSort($sort)
            ->setParamWhere($query)
            ->search();

        $cids = array_column($data['data'], 'id');

        $data['data'] = $this->batchGetInfoByIds($cids);

        return $data;
    }

    /**
     * 获取热门所有咨询师的id
     * @return array|bool
     * @throws \Exception
     */
    public function getHotCounselor()
    {
        $hot_cids = false;

        if ($this->cache_on >= 1)
        {
            $hot_cids = Cache::get(self::COUNSELOR_HOT_IDS);
        }

        // 获取所有咨询师id
        if ($hot_cids === false)
        {

            $where = ['counselor_status' => 1, 'is_hot' => 1];
            try
            {
                $hot_cids = $this
                    ->where($where)
                    ->order('is_hot DESC,accept DESC')
                    ->limit(0,10)
                    ->column('id');

                // 将咨询师id组成字符串
                if (!empty($hot_cids))
                {
                    $hot_cids = implode(',', $hot_cids);
                }

                // 缓存咨询师id,根据咨询师id
                if ($hot_cids && $this->cache_on >= 1)
                {
                    Cache::set(self::COUNSELOR_HOT_IDS, $hot_cids, self::CACHE_TIME);
                }

            }
            catch (\Exception $e)
            {
                $this->error = '获取上架的咨询师基本信息失败';

                return false;
            }

        }
        // 根据当前页咨询师id获取所需的咨询师信息
        return $this->batchGetInfoByIds($hot_cids);
    }

    /**
     * 从缓存中获取用户咨询师信息
     * @param $cids
     * @param array $field
     * @return array
     * @throws \Exception
     */
    public function batchGetInfoByUids($uid=0)
    {
        $cids = CacheManage::getInstance()->setCacheConfig('counselor_info', $uid)
            ->sGetIocData('list', function () use ($uid)
            {
                return $this->getUserCounselorIdFromData($uid);
            });

        return $this->batchGetInfoByIds($cids,['divination_level','stargazer_level','id']);
    }

    /**
     * 从数据库获取用户咨询师信息
     */
    public function getUserCounselorIdFromData($uid=0)
    {
        try
        {
            $data = $this
                ->where('uid', $uid)
                ->column('id');
        }
        catch (\Exception $e)
        {
            throw new ApiException('服务异常', 200, config('code.error'));
        }

        return $data;
    }

    /**
     * 通过IDS 在数据库中查找用户信息
     * @param array $ids
     * @return array
     * @throws ApiException
     */
    protected function getInfoByIdsInData(array $ids = [])
    {
        try
        {
            $data = $this->alias('c')
                ->whereIn('c.id', $ids)
                ->join('wechat_backup_07_18_14_43_00.app_user u', 'c.uid=u.id')
                ->column('c.id,c.create_time,c.update_time,c.counselor_status,c.is_hot,c.uid,c.divination_level,c.stargazer_level,c.divination_integral,c.stargazer_integral,c.state,c.star_level,c.divination_price,c.stargazer_price,c.counselor_num,c.accept,c.grab_num,c.read_num,c.answer_num,c.nickname,c.intro,u.avatar,u.sex', 'c.id');
        }
        catch (\Exception $e)
        {
            throw new ApiException('服务异常', 200, config('code.error'));
        }

        return $data;
    }

    /**
     * 批量通过咨询师ID获取咨询师信息
     * @param $cids
     * @param array $field
     * @return array
     * @throws \Exception
     */
    public function batchGetInfoByIds($cids, $field = [])
    {
        $cids = is_array($cids) ? $cids : explode(',', $cids);

        $data = CacheManage::getInstance()->setCacheConfig('counselor_info')
            ->batchGetCache($cids, function ($ids)
            {
                return $this->getInfoByIdsInData($ids);
            }, $field, 'list_details');

        return $data;
    }

    /**
     * 通过ID 获取咨询师信息
     * @param $cid
     * @param array $field
     * @return mixed
     * @throws \Exception
     */
    public function getInfoById($cid, $field = [])
    {
        $data = $this->batchGetInfoByIds($cid, $field);

        return current($data);
    }

    /**
     * 获取咨询师价格
     * @param $cids
     * @param int $problemType 占星/提问
     * @return array
     * @throws \Exception
     */
    public function getCounselorsPrice($cids, $problemType)
    {
        $problemTypeName = $problemType == 1 ? '占星' : '提问';

        if ($problemType == 1)
        {
            // 占星
            $field = 'id,stargazer_level,stargazer_price,state,counselor_status,nickname';
            $counselorLevel = 'stargazer_level';
            $counselorPrice = 'stargazer_price';
        } else
        {
            // 提问
            $field = 'id,divination_level,divination_price,state,counselor_status,nickname';
            $counselorLevel = 'divination_level';
            $counselorPrice = 'divination_price';
        }
        // 查下咨询师数据
        $data = $this->batchGetInfoByIds($cids, $field);
        // 咨询师参数校验
        if (count(explode(',', $cids)) != ($people = count($data)))
        {
            throw new Exception($problemTypeName . '师参数异常');
        }

        $priceData = [
            'totalPrice' => 0,
            'people' => $people,
            'counselorPrices' => []
        ];
        foreach ($data as $dataItem)
        {
            // 接单状态验证
            if ($dataItem['state'] === 0)
            {
                throw new Exception($problemTypeName . '师 ' . $dataItem['nickname'] . ' 休息了！...');
            }
            // 咨询师判断
            if ($dataItem['counselor_status'] != 1 || $dataItem[$counselorLevel] == 0)
            {
                throw new Exception($dataItem['nickname'] . ' ' . $problemTypeName . '师状态异常...');
            }
            // 统计总价
            $priceData['totalPrice'] += $dataItem[$counselorPrice];
            // 组合扩展对象
            $priceData['counselorPrices'][] = [
                'id' => $dataItem['id'],
                'level' => $dataItem[$counselorLevel],
                'price' => $dataItem[$counselorPrice],
                'nickname' => $dataItem['nickname']
            ];
        }
        // 返回价格信息
        return $priceData;
    }

    /**
     * 咨询师 积分更新
     * @param $counselorGrade
     * @param $counselorMode
     * @return array up_level=>咨询师升级信息
     * @throws \Exception
     */
    public function sucIntegrUpdate($counselorGrade, $counselorMode)
    {
        $cids = array_keys($counselorGrade);

        $counselorModel = new ZhunleCounselor();

        $cName = $counselorMode == 1 ? 'stargazer' : 'divination';
        // 获取咨询师信息
        $cInfos = $counselorModel->batchGetInfoByIds($cids, [$cName . '_level', $cName . '_integral', 'uid']);
        // 咨询师等级信息
        $counselorLevel = ZhunleCounselorLevel::getCounselorLevel($counselorMode);

        $result = [];
        $integralRecord = [];
        foreach ($cInfos as $cid => $counselorInfo)
        {
            $update = [
                $cName . '_integral' => $this->raw($cName . '_integral+' . $counselorGrade[$cid]['integral']),// 积分增加
                'answer_num' => $this->raw('answer_num+1'), // 回答次数增加
            ];

            $nextLevel = $counselorInfo[$cName . '_level'] + 1; // 下一个等级
            if (($counselorGrade[$cid]['integral'] + $counselorInfo[$cName . '_integral']) >= $counselorLevel[$nextLevel]['integral']) //判断等级是否提升
            {
                $update[$cName . '_level'] = $nextLevel;
                $update[$cName . '_price'] = $counselorLevel[$nextLevel]['price'];

                $result['up_level'][$cid] = [
                    'level' => $counselorLevel[$nextLevel]['level'],
                    'type' => $counselorMode,
                    'level_name' => $counselorLevel[$nextLevel]['name'],
                    'uid' => $counselorInfo['uid']
                ];
            }
            // 组合积分历史记录
            $integralRecord[] = [
                'c_id' => $cid,
                'ca_id' => $counselorGrade[$cid]['ca_id'],
                'integral' => $counselorGrade[$cid]['integral'],
                'create_time' => $counselorGrade[$cid]['create_time'],
                'counselor_mode' => $counselorMode,
            ];

            $this->where('id', $cid)->update($update);
        }

        (new ZhunleCounselorIntegralRecord())->saveAll($integralRecord); // 写入积分记录

        return $result;
    }

    /**
     * 咨询师 评分统计-->平均评分 采纳率-->更新
     * @param $data
     * @return bool
     * @throws Exception
     * @throws \Exception
     */
    public function integralStatistics($data)
    {
        $answerCommentModel = new ZhunleCounselorAnswerComment();

        $updateData = [];
        foreach ($data as $cid => $info)
        {
            $accept = $this->acceptStatistics($cid);
            // 统计 咨询师 评分
            $grade = $answerCommentModel->where('c_id', $cid)->avg('grade');
            // 格式化 评分
            $grade = round($grade, 1);
            // 组合更新咨询师数据
            $updateData[$cid] = [
                'star_level' => $grade,
                'accept' => $accept
            ];
            // 更新咨询师 用户点评 和缓存
            ZhunleCommentTag::updateCounselorComment($cid);
            // 更新咨询师星级
            $this->save($updateData[$cid], ['id' => $cid]);
        }
        // 更新咨询师信息缓存
        CacheManage::getInstance()->setCacheConfig('counselor_info')
            ->batchSetCache($updateData, 'list_details', true);

        return true;
    }

    /**
     * 获取 咨询师 采纳率
     * @param $cid
     * @return float|int
     * @throws Exception
     * @throws \Exception
     */
    protected function acceptStatistics($cid)
    {   // 获取采纳总次数
        $acceptNum = (new ZhunleCounselorAnswer())->where('c_id', $cid)->where('is_accept', 1)->count();

        if ($acceptNum == 0)
        {
            return $acceptNum;
        }

        $info = $this->getInfoById($cid, ['answer_num']);

        $accept = ($acceptNum / $info['answer_num']) / 100;

        $accept = round($accept, 1);

        return $accept;
    }
}
